﻿using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Runtime;
using System.Runtime.InteropServices;
using System.Runtime.Remoting.Proxies;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting;
using System.Web.Services;
using System.IO;
using System.Collections;
using System.ServiceModel.Activation;
using System.ServiceModel.Description;
using System.Threading;
using System.Diagnostics;
using System.ComponentModel;
using System.Reflection;
using System.Web.SessionState;

using PickGold.Base.Proxies;

namespace PickGold.Base.Remoting
{
	[Guid(MethodInvokerProxy.GUID)]
	abstract class MethodInvokerProxy : RealProxy, IDictionary<string, object>, IDisposable
	{
		private const string GUID = "B9E898BC-A549-478C-86F4-4050E6E119B2";
		public static readonly object InvokingKey = new object();
		/// <summary>
		/// LogicalCallContext
		/// </summary>
		public Dictionary<string, object> Items;
		/// <summary>
		/// 最后一次的调用消息
		/// </summary>
		public IMethodMessage Message;
		//public int Running = 0;

		/// <summary>
		/// 事件列表
		/// </summary>
		[NonSerialized]
		public EventHandlerList EventList = new EventHandlerList();//;//
		/// <summary>
		/// 调用事件
		/// </summary>
		public event InvokeMessageEventHandler Invoking
		{
			add
			{
				if (this.EventList == null)
					this.EventList = new EventHandlerList();
				this.EventList.AddHandler(InvokingKey, value);
			}
			remove
			{
				if (this.EventList == null)
					return;

				this.EventList.AddHandler(InvokingKey, value);
			}
		}

		/// <summary>
		/// 使用默认值初始化 System.Runtime.Remoting.Proxies.RealProxy 类的新实例。
		/// </summary>
		protected MethodInvokerProxy() : base() { }

		/// <summary>
		/// 初始化表示指定的 System.Type 的远程对象的 System.Runtime.Remoting.Proxies.RealProxy 类的新实例。
		/// </summary>
		/// <param name="classToProxy">为其创建代理的远程对象的 System.Type。</param>
		/// <exception cref="System.ArgumentException">classToProxy 不是一个接口，并且不是从 System.MarshalByRefObject 派生的。</exception>
		protected MethodInvokerProxy(Type classToProxy) : base(classToProxy) { }

		/// <summary>
		/// 初始化 System.Runtime.Remoting.Proxies.RealProxy 类的新实例。
		/// </summary>
		/// <param name="classToProxy">为其创建代理的远程对象的 System.Type。</param>
		/// <param name="stub">与新的代理实例相关联的存根 (Stub)。</param>
		/// <param name="stubData">为指定的存根 (Stub) 和新的代理实例设置的存根 (Stub) 数据。</param>
		/// <exception cref="System.ArgumentException">classToProxy 不是一个接口，并且不是从 System.MarshalByRefObject 派生的。</exception>
		protected MethodInvokerProxy(Type classToProxy, IntPtr stub, object stubData) : base(classToProxy, stub, stubData) { }

		#region IDictionary<string, object>

		public object this[string key]
		{
			get
			{
				if (this.Items == null)
					return null;

				return this.Items[key];
			}
			set
			{
				if (this.Items == null)
					this.Items = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
				this.Items[key] = value;
			}
		}

		public int Count
		{
			get
			{
				if (this.Items == null)
					return 0;

				return this.Items.Count;
			}
		}

		public bool IsReadOnly
		{
			get
			{
				if (this.Items == null)
					return false;

				//return this.Items.IsReadOnly;
				return false;
			}
		}

		public ICollection<string> Keys
		{
			get
			{
				if (this.Items == null)
					return null;

				return this.Items.Keys;
			}
		}

		public ICollection<object> Values
		{
			get
			{
				if (this.Items == null)
					return null;

				return this.Items.Values;
			}
		}

		public void Add(string key, object value)
		{
			if (this.Items == null)
				this.Items = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
			this.Items[key] = value;
		}

		public void Add(KeyValuePair<string, object> item)
		{
			if (this.Items == null)
				this.Items = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
			this.Items[item.Key] = item.Value;
		}

		public bool TryGetValue(string key, out object value)
		{
			if (this.Items == null)
			{
				value = null;
				return false;
			}

			return this.Items.TryGetValue(key, out value);
		}

		public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
		{
			//if (this.Items != null)
			//	this.Items.CopyTo(array, arrayIndex);
		}

		public bool Contains(KeyValuePair<string, object> item)
		{
			if (this.Items == null)
				return false;

			return this.Items.ContainsKey(item.Key);
		}

		public bool ContainsKey(string key)
		{
			if (this.Items == null)
				return false;

			return this.Items.ContainsKey(key);
		}

		public bool Remove(string key)
		{
			if (this.Items == null)
				return false;

			return this.Items.Remove(key);
		}

		public bool Remove(KeyValuePair<string, object> item)
		{
			if (this.Items == null)
				return false;

			return this.Items.Remove(item.Key);
		}

		public void Clear()
		{
			if (this.Items == null)
				this.Items.Clear();
		}

		public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
		{
			if (this.Items == null)
				return null;

			return this.Items.GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			if (this.Items == null)
				return null;

			return this.Items.GetEnumerator();
		}

		#endregion

		public void Dispose()
		{
			this.Dispose(true);
		}

		protected virtual void Dispose(bool disposing)
		{
		}

		public static void NotImplementedCallback(IAsyncResult asyncResult)
		{
			asyncResult.NotImplementedCallback();
		}

		protected static IMessage LocalInvoke<API>(API proxy, Dictionary<string, object> items, IMessage msg, InvokeMessageEventHandler handler)
		{
			var mcm = msg as IMethodCallMessage;
			if (mcm == null)
				return new ReturnMessage(new ArgumentNullException(MethodBase.GetCurrentMethod().GetParameters()[0].Name), mcm);

			if (proxy == null)
				return new ReturnMessage(new ObjectDisposedException(typeof(API).FullName), mcm);

			CMessage.SetThreadData(mcm, items);
			CMessage.ThreadHandler = proxy;
			CMessage.ThreadMessage = mcm;
			var e = Reflector.Generic<InvokeMessageEventArgs>.DefaultValue;
			if (handler != null)//AOP注入检查
			{
				e = new InvokeMessageEventArgs(mcm);
				handler(proxy, e);
				if (e.ReturnMessage != null)
				{
					CMessage.ThreadMessage = e.ReturnMessage;
					return e.ReturnMessage;
				}
			}

			try
			{
				var o = mcm.MethodBase.Invoke(proxy, mcm.Args);
				var os = new ArrayList();
				var ps = mcm.MethodBase.GetParameters();
				for (var i = 0; i < mcm.ArgCount; i++)
				{
					if (ps[i].ParameterType.IsByRef)
						os.Add(mcm.Args[i]);
				}
				var rm = new ReturnMessage(o, os.ToArray(), os.Count, null, mcm);
				CMessage.ThreadMessage = rm;
				if (e != null)
				{
					e.ReturnMessage = rm;
					handler(proxy, e);
				}
				return rm;
			}
			catch (Exception x)
			{
				var rm = new ReturnMessage(x.InnerException ?? x, mcm);//无法处理异步起始错误，直接返回错误。
				CMessage.ThreadMessage = rm;
				if (e != null)
				{
					e.ReturnMessage = rm;
					handler(proxy, e);
				}
				return rm;
			}
		}

		protected static IMessage RemoteInvoke<API>(IMethodInvoker real, Dictionary<string, object> items, IMessage msg, InvokeMessageEventHandler handler)
		{
			var mcm = msg as IMethodCallMessage;
			if (mcm == null)
				return new MethodInvokerReturnMessage(new ArgumentException(), mcm);

			if (real == null)
				return new MethodInvokerReturnMessage(new ObjectDisposedException(typeof(API).FullName), mcm);

			var mi = mcm.MethodBase as MethodInfo;
			if (mi != null)//判断是否为异步调用相关
			{
				var ps = mi.GetParameters();
				if (ps.Length == 1 && ps[0].ParameterType == typeof(IAsyncResult))//异步回调//结束异步调用
					return EndAsyncInvoke(mcm.InArgs[0] as IAsyncResult, real, mcm);

				if (mi.ReturnType != typeof(IAsyncResult) ||//返回值必须为异步状态对象
					ps.Length < 2 ||//参数必须有两个 callback, state
					ps.Length != mcm.ArgCount ||//参数总数与定义总数必须相等
					ps.Length != mcm.InArgCount ||//传入参数总数必须与定义总数相等，即没有传址（可返回）参数
					ps[ps.Length - 2].ParameterType != typeof(AsyncCallback) ||//倒数第二参数必须为回调函数
					ps[ps.Length - 1].ParameterType != typeof(object))//判断（开始异步的调用）
					mi = null;//设为空以标识为普通同步调用
			}
			var ms = new MemoryStream();
			var mic = mcm as MethodInvokerCallMessage;
			if (mic == null)
				mic = new MethodInvokerCallMessage(mcm);
			CMessage.ThreadHandler = real;
			CMessage.SetThreadData(mic, items);
			var cm = mic.Storage;
			var e = Reflector.Generic<InvokeMessageEventArgs>.DefaultValue;
			if (handler != null)
			{
				e = new InvokeMessageEventArgs(mcm);
				handler(real, e);
				if (e.ReturnMessage != null)
				{
					CMessage.ThreadMessage = e.ReturnMessage;
					return e.ReturnMessage;
				}
			}

			try
			{
				if (mi != null)//异步调用
				{
					var ar = CreateAsyncResultWrap(cm.Args[cm.Args.Length - 2] as AsyncCallback, cm.Args[cm.Args.Length - 1]);
					ar.Real = real;
					ar.Call = mcm;
					foreach (var value in cm.Properties.Values)
					{
						var v = value as object[];
						if (v == null || v.Length != cm.Args.Length)
							continue;

						for (var i = 0; i < v.Length; i++)
						{
							if (v[i] != cm.Args[i])
							{
								v = null;
								break;
							}
						}
						if (v == null)
							continue;

						v[v.Length - 2] = new AsyncCallback(NotImplementedCallback);
						v[v.Length - 1] = GUID;
					}
					if (cm.InArgs[cm.InArgs.Length - 2] == cm.Args[cm.Args.Length - 2])
						cm.InArgs[cm.InArgs.Length - 2] = new AsyncCallback(NotImplementedCallback);
					cm.Args[cm.Args.Length - 2] = new AsyncCallback(NotImplementedCallback);
					if (cm.InArgs[cm.InArgs.Length - 1] == cm.Args[cm.Args.Length - 1])
						cm.InArgs[cm.InArgs.Length - 1] = GUID;
					cm.Args[cm.Args.Length - 1] = GUID;
					cm.ProcessPropertiesProxy(true);
					cm.Serialize(ms);//序列化调用消息，非接口消息。
					ar.ResultWrap.WrapResult = real.BeginAsyncInvoke(ms.ToArray(), InvokeCallback, ar);
					var rm = new ReturnMessage(ar, null, 0, mcm.LogicalCallContext, mcm); ;
					CMessage.ThreadMessage = rm;
					if (e != null)
					{
						e.ReturnMessage = rm;
						handler(real, e);
					}
					return rm;
				}

				cm.ProcessPropertiesProxy(true);
				cm.Serialize(ms);//序列化调用消息，非接口消息。
				var m = ms.ToArray();
				m = real.Invoke(m);//执行。
				ms = new MemoryStream(m);
			}
			catch (Exception x)
			{
				var rm = new ReturnMessage(x.InnerException ?? x, msg as IMethodCallMessage);
				CMessage.ThreadMessage = rm;
				if (e != null)
				{
					e.ReturnMessage = rm;
					handler(real, e);
				}
				return rm;
			}

			var r = ms.Deserialize();//反序列化消息。
			var mrm = r as IMethodReturnMessage;
			if (mrm == null)
			{
				var m = r as CMethodReturnMessage;
				if (m != null)
				{
					m.ProcessPropertiesProxy(false);
					mrm = new MethodInvokerReturnMessage(m);
				}
			}
			CMessage.ThreadMessage = mrm;
			if (e != null)
			{
				e.ReturnMessage = mrm;
				handler(real, e);
			}
			return mrm;
		}

		public static void InvokeCallback(IAsyncResult result)
		{
			var wr = result.AsyncState as IAsyncResultWrap;
			wr.Complete();
		}

		public static AsyncInvokerResult CreateAsyncResultWrap(AsyncCallback callback, object state)
		{
			var ar = new AsyncInvokerResult(-1);
			ar.ResultWrap.WrapCallback = callback;
			ar.ResultWrap.AsyncState = state;
			return ar;
		}

		public static IMethodReturnMessage EndAsyncInvoke(IAsyncResult result, IMethodInvoker real, IMethodCallMessage methodCallMessage)
		{
			var rw = result as IAsyncInvokerResult;
			if (rw == null)
			{
				var x = new InvalidCastException("异步操作状态类型不正确，请传入原始状态对象！");
				if (methodCallMessage == null)
					throw x;

				return new ReturnMessage(x, methodCallMessage);
			}

			var rm = rw.WrapReturn as IMethodReturnMessage;
			if (rm == null)//如果远程返回的不是《方法调用返回消息》
			{
				var m = rw.WrapReturn as CMethodReturnMessage;
				if (m == null)//如果远程返回的不是《可序列化的方法调用返回消息》
				{
					if (methodCallMessage == null)
						rm = new MethodInvokerReturnMessage(rw.WrapReturn, null, null, null);
					else
						rm = new ReturnMessage(rw.WrapReturn, null, 0, methodCallMessage.LogicalCallContext, methodCallMessage);//只是消息结果
				}
				else
				{
					m.ProcessPropertiesProxy(false);
					rm = new MethodInvokerReturnMessage(m);
				}
			}
			//if (rm.Exception == null)//此处代码用于检测欲回调与实际回调不符的情况，影响性能，屏蔽之
			//{
			//    if (rm.MethodBase != null && rm.MethodBase != mcm.MethodBase)
			//        rm = new ReturnMessage(new MethodInvalidException(mcm, rm), mcm);//只是消息结果
			//}
			CMessage.ThreadMessage = rm;
			return rm;
		}
	}
}
